/**
 * 发布/订阅形式的socket模型封装
 * 订阅方式：
 *  obj.subscribe(事件，具柄) obj.unsubscribe
 *  obj.on(事件，具柄) obj.off()
 */
class Socket {

    /**
     * 初始化socket对象
     * @param {mixed} socket 已存在的socket对象或者发起新连接的url
     * @param  {...any} args 
     */
    constructor(socket, ...args) {

        // 创建socket
        if (socket.constructor == WebSocket) {
            this.socket = socket;
        } else {
            this.socket = new WebSocket(socket);
        }

        // this.socket.binaryType = 'arraybuffer';

        // 发布
        this.publish();


        // 存储订阅的事件集合
        this._events = {
            // 订阅的事件：执行的方法

        };

        // 定时验证的标识符
        this.heartBeatTimer;
        this.readyState;

    }

    // 发布socket事件
    publish() {

        this.readyState = 0;

        this.afterOpenEmit = [];

        // 执行socket连接 并初始化验证请求
        this.socket.addEventListener("open", evt => {
            // 连接状态的标识符
            this.readyState = this.socket.readyState;
            this.onOpen(evt);
        });

        // 接收socket数据
        this.socket.addEventListener("message", evt => {
            // 连接状态的标识符
            this.readyState = this.socket.readyState;
            this.onMessage(evt)
        });

        // 关闭socket连接
        this.socket.addEventListener("close", evt => {

            // 连接状态的标识符
            this.readyState = this.socket.readyState;
            this.onClose(evt);
        });

        // 请求发生错误
        this.socket.addEventListener("error", err => {
            // 连接状态的标识符
            this.readyState = this.socket.readyState;
            this.onError(err);
        });

    }

    // 发布后通知订阅者
    Notify(entry) {
        // 检查是否有订阅者 返回队列
        const cbQueue = this._events[entry.Event];
        if (cbQueue && cbQueue.length) {
            for (let handle of cbQueue) {
                if (handle instanceof Function) handle(entry.Data);
            }
        }
    }

    // 请求数据的方法
    onOpen(evt) {

        // 每隔20s检查连接
        this.heartBeatTimer = setInterval(() => this.send("ping"), 5000);

        // 通知订阅
        this.Notify({ Event: 'open', Data: evt });
    }

    /**
     * 订阅所有的数据，调用时 需要先检查连接状态
     * @param {mixed} params 订阅参数集合
     */
    send(params) {

        if (!this.checkOpen()) return;

        let type = Object.prototype.toString.call(params);

        switch (type) {
            case "[object Object]":
                this.socket.send(JSON.stringify(params));
                break;
            case "[object Array]":
                for (let item of params) {
                    this.socket.send(JSON.stringify(item));
                }
                break;
            default:
                // debugger
                this.socket.send(params);
                break;
        }
    }

    onMessage(evt) {

        if (evt.data.toLowerCase() == "pong") {
            return;
        }

        try {

            // 解析推送的数据

            const data = JSON.parse(evt.data);

            // 通知订阅者
            this.Notify({
                Event: 'message',
                Data: data
            });

        } catch (err) {
            console.error(' >> Data parsing error:', err.message);

            // 通知订阅者
            this.Notify({
                Event: 'error',
                Data: err
            });
        }
    }

    // 添加事件监听
    on(name, handler) {
        this.subscribe(name, handler);
    }

    // 取消订阅事件
    off(name, handler) {
        this.unsubscribe(name, handler);
    }

    // 订阅事件
    subscribe(name, handler) {

        if (this._events.hasOwnProperty(name)) {
            this._events[name].push(handler); // 追加事件
        } else {
            this._events[name] = [handler]; // 添加事件
        }
    }

    // 取消订阅
    unsubscribe(name, handler) {

        let start = this._events[name].findIndex(item => item === handler);

        // 删除该事件
        this._events[name].splice(start, 1);

    }

    /*
        0 (WebSocket.CONNECTING) 正在链接中 
        1 (WebSocket.OPEN) 已经链接并且可以通讯 
        2 (WebSocket.CLOSING) 连接正在关闭 
        3 (WebSocket.CLOSED) 连接已关闭或者没有链接成功
    */
    checkOpen() {
        return this.readyState == 1 || this.readyState == 2;
    }

    onClose(evt) {

        // 先执行订阅事件 再销毁一切环境
        this.Notify({ Event: 'close', Data: evt });
        this._events = {};
        this.socket = null;
    }


    onError(err) {
        this.Notify({ Event: 'error', Data: err });
    }

    // emit(data) {
    //     return new Promise((resolve) => {
    //         this.send(JSON.stringify(data));
    //         this.on('message', function (data) {
    //             resolve(data);
    //         });
    //     });
    // }

    doClose() {
        // 检测是否已经连接
        if (this.readyState > 0) {
            // 必须先将readyState状态 设为3，防止过程中 心跳执行send 报错
            this.readyState = 3;
            // 去除心跳机
            if (this.heartBeatTimer) {
                clearInterval(this.heartBeatTimer);
                this.heartBeatTimer = null;
            }
            // 开始关闭连接，会触发close事件的订阅者 
            this.socket.close();
        }
    }


}

export default Socket
